package ngat.oss;

import ngat.phase2.*;
import ngat.phase2.nonpersist.*;
import ngat.util.*;
import ngat.util.logging.*;
import ngat.util.charting.*;
import ngat.astrometry.*;
import ngat.instrument.*;

import dev.lt.*;

import jyd.dbms.*;
import jyd.storable.*;
import jyd.collection.*;

import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;

import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;

import java.io.*;
import java.awt.*;
import java.util.*;
import java.text.*;
import javax.swing.*;

/** This class will act as a base for constructing various Database administration and lookup
 * utilities.
 */
public class DBUtil {

    public static final int    ADMIN_LOCK = 666;

    public static final String ADMIN_USER = "TMC ADMIN";

    public static final long   ADMIN_REG  = 0xAABBCCDDL;

    public static final String STUB_COMMENT = "Initial stub entry";

    public static final String OSS_USER = "OSS";

    public static final long   OSS_REG  = 0xCCAABBEEL;

    /** Classname for logs.*/
    public static final String CLASS = "DBUtil";

    /** Action code: No action to perform.*/
    public static final String NO_ACTION = "no-action";
    
    /** Command arg delimiter.*/
    public static final String DELIM = "@";

    public static final String DB_NAME = "LT_Phase2_001";
    
    public static final String DB_DIR = "/occ/oss";
    
    /** DB transaction for this operation.*/
    protected Transaction trans;

    static long cpid = 0L;

    public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss-z");
    public static SimpleDateFormat pdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    public static SimpleDateFormat hrf = new SimpleDateFormat("dd'('HH:mm')'");
    public static SimpleDateFormat dayf= new SimpleDateFormat("dd'('HH')'");

    public static SimpleTimeZone UTC = new SimpleTimeZone(0, "UTC");
    
    protected File dbDirName;

    protected String dbRootName;

    protected Logger logger;

    private boolean shutdown = true;
    
    /** Create DBUtil on the specified DB directory.*/
    public DBUtil(File dbDirName, String dbRootName) {	
	this.dbDirName  = dbDirName;		
	this.dbRootName = dbRootName;
	sdf.setTimeZone(UTC);
	pdf.setTimeZone(UTC);
	hrf.setTimeZone(UTC);
	dayf.setTimeZone(UTC);
    }
    
    /** Run DBUtil.*/
    public static void main(String args[]) {

	String dbDirName = System.getProperty("db.dir", DB_DIR);

	String dbRootName = System.getProperty("db.name", DB_NAME);

	DBUtil db = new DBUtil(new File(dbDirName), dbRootName);
	
	// The action is passed as a System property.
	String actionName = System.getProperty("db.action", NO_ACTION);

	// Swap character.
	String swapChar = System.getProperty("cp.swap", "%");
	
	// The args are parsed into a ConfigProperties.
	CommandParser parser = new CommandParser(DELIM, swapChar.charAt(0));
    
	try {
	    parser.parse(args);
	} catch (ParseException px) {
	    System.err.println("Error parsing command args for DBUtil: "+px);
	    return;
	}
	
	ConfigurationProperties params = parser.getMap();
	
	db.init();
	  
	db.exec(actionName, params);

    }
    
    /** Initialize.*/
    public void init() {
	OSS_Utilities.setDatabaseDir(dbDirName);
	OSS_Utilities.setRootName(dbRootName);

	File dbFile = new File(dbDirName, "phase2.s0");
	
	Logger logger = LogManager.getLogger("INFO");
	logger.setLogLevel(Logging.ALL);
    
	LogHandler console = new ConsoleLogHandler(new SimpleLogFormatter());
	console.setLogLevel(Logging.ALL);
	
	logger.addHandler(console);
    }

    /** Execute the command .*/
    public void exec(String actionName, ConfigurationProperties params) {
	// Choose the action to perform with supplied params. 
	try { 
	    trans = Transaction.current();
	    selectAction(actionName, params);
	} catch (Exception ex) {
	    System.err.println("DBUtil: Error executing: "+actionName+" : "+ex); 
	    ex.printStackTrace();
	} finally { 	   	   
	    Transaction.current().commit();
	    System.err.println("DBUtil: Committed transaction");
	    DBRuntime.shutDown(shutdown);	  
	}
    }

    /** Select the action to perform based on the supplied action string, 
     * and passing the specified parameters.
     */
    public void selectAction(String actionName, ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	// SHOW_PROPOSAL_ACTION
	if (actionName.equals("create-db")) {
	    createDatabaseAction(params);
	} else if
	    (actionName.equals("show-all")) {
	    showAllAction(params);	
	} else if
	    (actionName.equals("list-tags")) {
	    listTagsAction(params);	
	} else if
	    (actionName.equals("add-tag")) {
	    addTagAction(params);
	} else if
	    (actionName.equals("remove-tag")) {
	    removeTagAction(params);
	} else if
	    (actionName.equals("show-tag")) {
	    showTagAction(params);
	} else if
	    (actionName.equals("list-users")) {
	    listUsersAction(params);
	} else if
	    (actionName.equals("list-all-users")) {
	    listAllUsersAction(params);
	} else if
	    (actionName.equals("add-user")) {
	    addUserAction(params);	
	} else if
	    (actionName.equals("add-co-user")) {
	    addCoUserAction(params);
	} else if
	    (actionName.equals("show-user")) {
	    showUserAction(params);   
	} else if
	    (actionName.equals("delete-user")) {
	    deleteUserAction(params);   
	} else if
	    (actionName.equals("list-proposals")) {
	    listProposalsAction(params);
	} else if
	    (actionName.equals("list-coi-proposals")) {
	    listCoIProposalsAction(params);
	} else if 	    
	    (actionName.equals("add-proposal")) {
	    addProposalAction(params);
	} else if 
	    (actionName.equals("show-proposal")) {
	    showProposalAction(params);
	} else if 
	    (actionName.equals("clear-proposal")) {
	    clearProposalAction(params);
	} else if 
	    (actionName.equals("unlock-proposal")) {
	    unlockProposalAction(params);
	} else if 
	    (actionName.equals("lock-proposal")) {
	    lockProposalAction(params);
	} else if 
	    (actionName.equals("add-revision")) {
	    addRevisionAction(params);
	} else if 
	    (actionName.equals("clear-revisions")) {
	    clearRevisionsAction(params);
	} else if 
	    (actionName.equals("add-group")) {
	    addGroupAction(params);
	} else if 
	    (actionName.equals("update-group")) {
	    updateGroupAction(params);
	} else if 
	    (actionName.equals("remove-group")) {
	    removeGroupAction(params);	    
	} else if 
	    (actionName.equals("check-group")) {
	    checkGroupAction(params);
	} else if 
	    (actionName.equals("show-group")) {
	    showGroupAction(params);
	} else if 
	    (actionName.equals("add-inst-cfg")) {
	    addInstConfigAction(params);
	} else if 
	    (actionName.equals("add-tel-cfg")) {
	    addTeleConfigAction(params);
	} else if 
	    (actionName.equals("add-source")) {
	    addSourceAction(params);
	} else if 
	    (actionName.equals("add-obs")) {
	    addObservationAction(params);
	} else if 
	    (actionName.equals("show-obs")) {
	    showObservationAction(params);
	} else if 
	    (actionName.equals("list-targets")) {
	    listAllTargetsAction(params);
	} else if 
	    (actionName.equals("plot-schedule")) {
	    plotScheduleAction(params);
	} else if 
	    (actionName.equals("unlock-all-proposals")) {
	    unlockAllProposalsAction(params);
	} else if 
	    (actionName.equals("switch-all")) {
	    switchAllProposalsAction(params);
	} else if
	    (actionName.equals("xml-dump")) {
	    xmlDumpAction();

	} else if
	    (actionName.equals("grp-see")) {
	    groupSeeAction();
	    
	} else if
	    (actionName.equals("gen-ids")) {
	    genIdsAction();
	} else if
	    (actionName.equals("create-id")) {
	    createIDMapAction();
	    
	    //} else if 
	    //(actionName.equals("list-obs")) {
	    //listObservationsAction(params);
	} else {
	    throw new IllegalArgumentException("No such action available");	    
	}
    }
    
    /** Action: SHOW_ALL. 
     */
    public void  xmlDumpAction() 	throws IllegalArgumentException, IOException {
		
	Root root = OSS_Utilities.fetchRoot();
	
	// Check it exists.
	if (root == null) {		
	    throw new IllegalArgumentException("Root not found");
	} 

	Element xroot = new Element("db");
	Document doc = new Document(xroot);
	xroot.setAttribute("name", xroot.getName());

	Iterator iTag = root.listAllTags();
	while (iTag.hasNext()) {
	    
	    Tag tag = (Tag)iTag.next();
	 
	    Element xtag = new Element("tag");
	    xtag.setAttribute("name", tag.getName());
	    xroot.addContent(xtag);
   	
	    Iterator iUser = tag.listAllUsers();
	    while (iUser.hasNext()) {
		
		User user = (User)iUser.next();
		
		Element xuser = new Element("user");
		xuser.setAttribute("name", user.getName());
		xtag.addContent(xuser);

		Iterator it = user.listAllProposals();
		while (it.hasNext()) {
		    
		    KVPair pair = (KVPair)it.next();
		    String name = (String)pair.getKey();
		    
		    //System.err.println("Looking for proposal: "+name);

		    Proposal proposal = null;
		    try {
			proposal = OSS_Utilities.fetchProposal(new Path(user.getFullPath(), name));
		    } catch (Exception ex) {
			System.err.println("\n\n\n Proposal: "+user.getFullPath()+"/"+name+"     -- error reading from DB: "+ex);
		    }

		    if (proposal != null) {			
		
			Element xprop = new Element("proposal");
			xprop.setAttribute("name", proposal.getName());
			xuser.addContent(xprop);

		    } else {
			System.err.println("\n\n\n Proposal: "+user.getFullPath()+"/"+name+"    -- NULL");
		    }

		}
	    }
	}

	SAXBuilder builder = new SAXBuilder();
	builder.setIgnoringElementContentWhitespace(true);

	XMLOutputter outp = new XMLOutputter(org.jdom.output.Format.getPrettyFormat());
	outp.output(doc, new FileOutputStream("db.xml"));
    
    }

    /** Action: SHOW_ALL. 
     */
    public void showAllAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {


	Root root = OSS_Utilities.fetchRoot();
	
	// Check it exists.
	if (root == null) {		
	    throw new IllegalArgumentException("Root not found");
	} 
	
	Iterator iTag = root.listAllTags();
	while (iTag.hasNext()) {
	    
	    Tag tag = (Tag)iTag.next();
	    
	    tag.getName();
	    
	    System.err.println("\n\n\n=======================================================");
	    System.err.println("Tag: "+tag.toString());
	    
	    Iterator iUser = tag.listAllUsers();
	    while (iUser.hasNext()) {
		
		User user = (User)iUser.next();
		
		user.getName();
		
		System.err.println("\n\n\n=======================================================");
		System.err.println("User: "+user.toString());
		
		Iterator it = user.listAllProposals();
		while (it.hasNext()) {
		    
		    KVPair pair = (KVPair)it.next();
		    String name = (String)pair.getKey();
		    
		    //System.err.println("Looking for proposal: "+name);

		    Proposal proposal = null;
		    try {
			proposal = OSS_Utilities.fetchProposal(new Path(user.getFullPath(), name));
		    } catch (Exception ex) {
			System.err.println("\n\n\n Proposal: "+user.getFullPath()+"/"+name+"     -- error reading from DB: "+ex);
		    }

		    if (proposal != null) {			
			printProposal(proposal);
		    } else {
			System.err.println("\n\n\n Proposal: "+user.getFullPath()+"/"+name+"    -- NULL");
		    }

		}
	    }
	}
    }


    /** Action: GRPSEE. Group Seeing.
     *
     */
    public void groupSeeAction() 
	throws IllegalArgumentException, IOException {

		Root root = OSS_Utilities.fetchRoot();
	
	// Check it exists.
	if (root == null) {		
	    throw new IllegalArgumentException("Root not found");
	} 
	
	Iterator iTag = root.listAllTags();
	while (iTag.hasNext()) {
	    
	    Tag tag = (Tag)iTag.next();	    
	    tag.getName();
		    
	    Iterator iUser = tag.listAllUsers();
	    while (iUser.hasNext()) {
		
		User user = (User)iUser.next();		
		user.getName();
	
		Iterator it = user.listAllProposals();
		while (it.hasNext()) {
		    
		    KVPair pair = (KVPair)it.next();
		    String name = (String)pair.getKey();
		  
		    Proposal proposal = null;
		    try {
			proposal = OSS_Utilities.fetchProposal(new Path(user.getFullPath(), name));
		    } catch (Exception ex) {
			System.err.println("**Proposal: "+user.getFullPath()+"/"+name+"     -- error reading from DB: "+ex);
		    }

		    if (proposal != null) {			
		
			Iterator ig = proposal.listAllGroups();
			while (ig.hasNext()) {
			    
			    Group group = (Group)ig.next();
			    if (group.getMinimumSeeing() == Group.AVERAGE ||
				group.getMinimumSeeing() == Group.EXCELLENT)
				System.err.println(group.getFullPath()+" : "+
						   group.toSeeingString(group.getMinimumSeeing())+" : "+
						   (group.getPhotometric() ? "PHOTOM" : "SPECTRO"));
			    
			}
			
		    } else {
			System.err.println("**Proposal: "+user.getFullPath()+"/"+name+"    -- NULL");
		    }

		}
	    }
	}


    }
   public void genIdsAction() 
 	throws IllegalArgumentException, IOException {}
    
    //    /** Action: GEN_ID. Generate IDs for DB objects.
    //      *
//      */
//     public void genIdsAction() 
// 	throws IllegalArgumentException, IOException {
	
// 	Transaction trans = Transaction.current();	
// 	trans.abort();
// 	Map rootMap   = trans.parent().root();
// 	if (rootMap == null) 
// 	    throw new IllegalArgumentException("Rootmap not found");

// 	System.err.println("DBU::GenID:Got rootMap");

// 	// JDBC Connection thingy
// 	java.sql.Connection conn;
// 	try {
// 	    Class.forName("com.mysql.jdbc.Driver").newInstance();	
// 	    conn = DriverManager.getConnection(
// 					       "jdbc:mysql://localhost/ngat_testdb?user=root&password=appletart99ax");
// 	    System.err.println("SQL Driver got connection: "+conn);
// 	} catch (Exception e) {
// 	    e.printStackTrace();
// 	    throw new IllegalArgumentException("Error creating SQL Connection to IDMAP Table:");	    
// 	}

// 	// Root thingy
// 	Root root = (Root)rootMap.get(dbRootName);	
// 	System.err.println("DBU::GenID:Retrieved root: "+root);
	
// 	// Check it exists.
// 	if (root == null) 		
// 	    throw new IllegalArgumentException("Fecking [Root] not found");
	
	
// 	int idc = 0;
// 	String key = null;
	
// 	Iterator iTag = root.listAllTags();
// 	while (iTag.hasNext()) {
	    
// 	    Tag tag = (Tag)iTag.next();	    
// 	    tag.getName();
	    
// 	    System.err.println("DBU::GenID:Tag: "+tag.getName()+" ["+(++idc)+"]");
// 	    key = "TAG:"+tag.getName();
// 	    putid(conn, key); 
	   
// 	    Iterator iUser = tag.listAllUsers();
// 	    while (iUser.hasNext()) {
		
// 		User user = (User)iUser.next();
		
// 		key = "USR:"+tag.getName()+"/"+user.getName();
// 		System.err.println("DBU::GenID:User: "+user.getName()+" ["+(++idc)+"]");		
// 		putid(conn, key); 	
	   
// 		Iterator it = user.listAllProposals();
// 		while (it.hasNext()) {
		    
// 		    KVPair pair = (KVPair)it.next();
// 		    String name = (String)pair.getKey();
		    
// 		    Proposal proposal = null;
// 		    try {
// 			proposal = OSS_Utilities.fetchProposal(new Path(user.getFullPath(), name));
// 		    } catch (Exception ex) {
// 			System.err.println("\n\n\n Proposal: "+user.getFullPath()+"/"+name+"     -- error reading from DB: "+ex);
// 		    }
		    
// 		    if (proposal != null) {
// 			TmpAccount acc = null;
// 			String pkey = tag.getName()+"/"+user.getName()+"/"+proposal.getName();
// 			System.err.println("DBU::GenID:Proposal: "+proposal.getName()+" ["+(++idc)+"]");
// 			putid(conn, "PROP:"+pkey);
			
// 			System.err.println("DBU::GenID:Account: "+proposal.getName()+" TOTAL ["+(++idc)+"]");
// 			key = pkey+"/TOTAL";
// 			putid(conn, "ACC:"+key);
// 			acc = new TmpAccount();
// 			proposal.getPipelineConfigs().put("TOTAL", acc);
		
// 			System.err.println("DBU::GenID:Account: "+proposal.getName()+" FIXED ["+(++idc)+"]");
// 			key = pkey+"/FIXED";
// 			putid(conn, "ACC:"+key);
// 			acc = new TmpAccount();
// 			proposal.getPipelineConfigs().put("FIXED", acc);
		
// 			System.err.println("DBU::GenID:Account: "+proposal.getName()+" DKPR  ["+(++idc)+"]");
// 			key = pkey+"/DKPR";
// 			putid(conn, "ACC:"+key);
// 			acc = new TmpAccount();
// 			proposal.getPipelineConfigs().put("DKPR", acc);
			
// 			System.err.println("DBU::GenID:Account: "+proposal.getName()+" DKAV  ["+(++idc)+"]");
// 			key = pkey+"/DKAV";
// 			putid(conn, "ACC:"+key);
// 			acc = new TmpAccount();
// 			proposal.getPipelineConfigs().put("DKAV", acc);
		
// 			System.err.println("DBU::GenID:Account: "+proposal.getName()+" DKEX  ["+(++idc)+"]");
// 			key = pkey+"/DKEX";
// 			putid(conn, "ACC:"+key);
// 			acc = new TmpAccount();
// 			proposal.getPipelineConfigs().put("DKEX", acc);
			
// 			System.err.println("DBU::GenID:Account: "+proposal.getName()+" BRPR  ["+(++idc)+"]");
// 			key = pkey+"/BRPR";
// 			putid(conn, "ACC:"+key);
// 			acc = new TmpAccount();
// 			proposal.getPipelineConfigs().put("BRPR", acc);
		
// 			System.err.println("DBU::GenID:Account: "+proposal.getName()+" BRAV  ["+(++idc)+"]");
// 			key = pkey+"/BRAV";
// 			putid(conn, "ACC:"+key);
// 			acc = new TmpAccount();
// 			proposal.getPipelineConfigs().put("BRAV", acc);
		
// 			System.err.println("DBU::GenID:Account: "+proposal.getName()+" BREX  ["+(++idc)+"]");
// 			key = pkey+"/BREX";
// 			putid(conn, "ACC:"+key);
// 			acc = new TmpAccount();
// 			proposal.getPipelineConfigs().put("BREX", acc);
			
// 			Iterator ig = proposal.listAllGroups();
// 			while (ig.hasNext()) {
			    
// 			    Group group = (Group)ig.next();
// 			    System.err.println("DBU::GenID:Group: "+group.getName()+"["+(++idc)+"]");
// 			    key = "GRP:"+tag.getName()+"/"+user.getName()+"/"+proposal.getName()+"/"+group.getName();
// 			    putid(conn, key);
			   
// 			    Iterator io = group.listAllObservations();
// 			    while (io.hasNext()) {
				
// 				Observation obs = (Observation)io.next();
// 				System.err.println("DBU::GenID:Obs: "+obs.getName()+"["+(++idc)+"]");
// 				key = "OBS:"+tag.getName()+"/"+user.getName()+"/"+proposal.getName()+"/"+group.getName()+"/"+obs.getName();
// 				putid(conn, key);
			
// 			    }

// 			    java.util.List h = (java.util.List)group.getHistory();
// 			    int kk = 0;
// 			    if (h != null) {
// 				Iterator ih = h.iterator();
// 				while (ih.hasNext()) {
// 				    Group.History hist = (Group.History)ih.next();
// 				    System.err.println("DBU::GenID:History item: "+hist.toString()+"["+(++idc)+"]");
// 				    key = "H:"+tag.getName()+"/"+user.getName()+"/"+proposal.getName()+"/"+group.getName()+"/"+(++kk);
// 				    putid(conn, key);				 
// 				}
// 			    }
			 
   
// 			}
			
// 			Iterator is = proposal.listAllSources();
// 			while (is.hasNext()) {
			    
// 			    Source source = (Source)is.next();
// 			    System.err.println("DBU::GenID:Source: "+source.getName()+"["+(++idc)+"]");
// 			    key = "SRC:"+tag.getName()+"/"+user.getName()+"/"+proposal.getName()+"/"+source.getName();
// 			    putid(conn, key);			  
// 			}

// 			try {
// 			    OSS_Utilities.storeProposal(proposal);
// 			} catch (Exception e) {
// 			    System.err.println("**** ERROR SAVING Proposal: "+proposal.getName());
// 			    e.printStackTrace();
// 			}

// 		    } else {
// 			System.err.println("\n\n\n Proposal: "+user.getFullPath()+"/"+name+"    -- NULL");
// 		    }
		    
		    
// 		} // next prop

// 	    } // next user

// 	} // next tag
	
//     } // (gen-ids)

    private void putid(java.sql.Connection connection, String key) {
	
	try {
	    Statement statement = connection.createStatement();
	    String update = "insert into idmap (path) values('"+key+"')";
	    statement.executeUpdate(update);
       } catch (Exception e) {
           e.printStackTrace();
       }

	System.err.println("CPID["+(++cpid)+"]DBU::GenID:Saving ID in Mysql for ["+key+"]");
	
    }
    
    /** Action: CREATE_DB. Create a new empty Database.
     * Param: name The name of the database.
     *
     */
    public void createDatabaseAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	String databaseName = params.getProperty("name");
	if (databaseName == null) 
	    throw new IllegalArgumentException("No database name specified");
	
	Map rootMap = trans.parent().root();
	System.err.println("Got rootMap");
	//SortedMap rootEntry = new StorableSortedDictionary();
	//rootMap.put("ROOT", rootEntry);

		
	Root root = new Root(dbRootName);
	root.setSchedCoeff(1.0f);
	System.err.println("Created root:"+root.getName());
	///rootEntry.put(root.getName(), root);	  
	
	rootMap.put(root.getName(), root);	  

	// At this point we need to move the db files to the correct p2/subdir
	
	System.err.println("Should now move stuff to: "+new File(DB_DIR, "phase2/"+databaseName));
	
    }

    /** Action: CREATE_IDMAP. Create a new IDMAP.
     *
     */
    public void createIDMapAction() 
	throws IllegalArgumentException, IOException {

	Transaction trans = Transaction.current();	
	trans.abort();
	Map rootMap   = trans.parent().root();
	if (rootMap == null) 
	    throw new IllegalArgumentException("Rootmap not found");

	System.err.println("DBU::GenID:Got rootMap");
	
	SerializableStorableSortedDictionary idmap = new SerializableStorableSortedDictionary();
	
	rootMap.put("IDMAP", idmap);	  

	SerializableStorableSortedDictionary pathmap = new SerializableStorableSortedDictionary();
	
	rootMap.put("PATHMAP", pathmap);	  

	
    }
    
    /** Action: ADD_TAG. Adds a TAG to the Root entry.
     *
     */
    public void addTagAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String tagName = params.getProperty("name");
	if (tagName == null) 
	    throw new IllegalArgumentException("No TAG name specified");

	float targetBP = params.getFloatValue("targetBP", 0.0f);
	float targetBA = params.getFloatValue("targetBA", 0.0f);
	float targetBX = params.getFloatValue("targetBX", 0.0f);
	
	float targetDP = params.getFloatValue("targetDP", 0.0f);
	float targetDA = params.getFloatValue("targetDA", 0.0f);
	float targetDX = params.getFloatValue("targetDX", 0.0f);

	float total = params.getFloatValue("total", 0.0f);
	
	Root root = OSS_Utilities.fetchRoot();
	
	// Check for root.
	if (root == null)
	    throw new IllegalArgumentException("Could not find Root:");
	 
	Tag tag = new Tag(tagName);

	tag.setTotalAllocatedTime(total);

	tag.setTargetFraction(Proposal.BRIGHT, Proposal.POOR,      targetBP);
	tag.setTargetFraction(Proposal.BRIGHT, Proposal.AVERAGE,   targetBA);
	tag.setTargetFraction(Proposal.BRIGHT, Proposal.EXCELLENT, targetBX);
	tag.setTargetFraction(Proposal.DARK,   Proposal.POOR,      targetDP);
	tag.setTargetFraction(Proposal.DARK,   Proposal.AVERAGE,   targetDA);
	tag.setTargetFraction(Proposal.DARK,   Proposal.EXCELLENT, targetDX);

	root.addTag(tag);

	System.err.println("Added TAG: "+tag.getFullPath());

    }

    /** Action: REMOVE_TAG. Remove a TAG.
     *
     */
    public void removeTagAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String tagPathName = params.getProperty("path");
	if (tagPathName == null)
	    throw new IllegalArgumentException("No Tag specified");

	Path tagPath = new Path("/"+dbRootName, tagPathName);
	Tag  tag     = OSS_Utilities.fetchTag(tagPath);

	if (tag == null)
	    throw new IllegalArgumentException("No such Tag ["+tagPathName+"] found");

	Root root = OSS_Utilities.fetchRoot();
	root.deleteTag(tag);
    	 
    }

    /** Action: SHOW_TAG. Displays details of a TAG to stderr.
     *
     */
    public void showTagAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String tagPathName = params.getProperty("path");
	if (tagPathName == null)
	    throw new IllegalArgumentException("No Tag specified");

	Path tagPath = new Path("/"+dbRootName, tagPathName);
	Tag  tag     = OSS_Utilities.fetchTag(tagPath);

	if (tag == null)
	    throw new IllegalArgumentException("No such Tag ["+tagPathName+"] found");

	System.err.println(tag.getName());

	System.err.println(tag.toString());
    	 
    }


     /** Action: LIST_TAGS. Displays the set of Tags to stderr.
     *
     */
    public void listTagsAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	 Root root = OSS_Utilities.fetchRoot();
	    
	 // Check for root.
	 if (root == null)
	     throw new IllegalArgumentException("Could not find Root:");
	 
	 // Iterate round the Root's Tags.
	 Iterator it = root.listAllTags();

	 System.err.print("[");
	 while (it.hasNext()) {
	     Tag tag = (Tag)it.next();
	     System.err.print(tag.getFullPath()+":");
	 }	
	 System.err.println("]");

	 // [T1:T2:T3:]
    	 
    }

    /** Action: ADD_USER. Adds a User to a TAG.
     * Param: tag The Tag to add to.
     * Param: sname, fname, addr1,, addr3, country, institution.
     *
     */
    public void addUserAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {

	String userName = params.getProperty("name");
	if (userName == null) 
	    throw new IllegalArgumentException("No User name specified");
	
	String tagPathName = params.getProperty("path");
	if (tagPathName == null)
	    throw new IllegalArgumentException("No Tag specified");
	
	Path tagPath = new Path("/"+dbRootName, tagPathName);
	Tag  tag     = OSS_Utilities.fetchTag(tagPath);
	
	if (tag == null)
	    throw new IllegalArgumentException("No such Tag ["+tagPathName+"] found");

	User user = new User(userName);

	String sname = params.getProperty("sname");
	String fname = params.getProperty("fname");

	String email = params.getProperty("email");

	String tel   = params.getProperty("tel");
	String fax   = params.getProperty("fax");

	String addr1 = params.getProperty("addr1");
	String addr2 = params.getProperty("addr2");
	String addr3 = params.getProperty("addr3");

	String org   = params.getProperty("organization");
	String ctry  = params.getProperty("country");

	String pCode = params.getProperty("postcode");

	user.setSname(sname);
	user.setFname(fname);

	user.setEmail(email);

	user.setTelephone(tel);
	user.setFax(fax);

	user.setAddress1(addr1);
	user.setAddress2(addr2);
	user.setAddress3(addr3);

	user.setOrganization(org);

	user.setCountry(ctry);

	user.setPostalCode(pCode);

	tag.addUser(user);

	System.err.println("Added user: "+user);

    }

    /** Action: SHOW_USER. Displays details of a user to stderr.
     *
     */
    public void showUserAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String userPathName = params.getProperty("path");
	if (userPathName == null)
	    throw new IllegalArgumentException("No User specified");

	Path userPath = new Path("/"+dbRootName, userPathName);
	User user     = OSS_Utilities.fetchUser(userPath);

	if (user == null)
	    throw new IllegalArgumentException("No such User ["+userPathName+"] found");

	System.err.println(user.toString());
    	 
    }

    /** Action: ADD_CO_USER.Adds a Co-user to a Proposal.
     *
     */
    public void addCoUserAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	
	String proposalPathName = params.getProperty("path");
	if (proposalPathName == null)
	    throw new IllegalArgumentException("No Proposal specified");

	Path     proposalPath = new Path("/"+dbRootName, proposalPathName);
	Proposal proposal     = OSS_Utilities.fetchProposal(proposalPath);

	if (proposal == null)
	    throw new IllegalArgumentException("No such Proposal ["+proposalPathName+"] found");


       	String couserPathName = params.getProperty("co-user");
	if (couserPathName == null)
	    throw new IllegalArgumentException("No Co-user specified");

	Path couserPath = new Path("/"+dbRootName, couserPathName);
	User couser     = OSS_Utilities.fetchUser(couserPath);

	if (couser == null)
	    throw new IllegalArgumentException("No such Co-user ["+couserPathName+"] found");
	
	couser.addCoIProposal(proposalPath.toString());
	
	System.err.println("DBU::User: "+couserPathName+" added CoI Prop: "+proposalPath.toString()+
			   " User now has: "+couser.getCoIProposals().size()+" cops");
	
    }

    /** Action: DELETE_USER.Deletes a User.
     * Param: path The User's full path (ex. /root/T1/john.smith).
     */
    public void deleteUserAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	String userPathName = params.getProperty("path");
	if (userPathName == null) 
	    throw new IllegalArgumentException("No User specified");
    
	Path userPath = new Path("/"+dbRootName, userPathName);

	Tag tag = OSS_Utilities.fetchTag(userPath);

	if (tag == null)
	     throw new IllegalArgumentException("No Tag for["+userPathName+"] found.");

	// TAG is found - check if its a null user.

	String uname = userPath.getUserByName();

	System.err.println("Specified user-name is: ["+(uname != null ? uname : "NULL")+"]");

	if (uname == null ||
	    uname.equals("")) {
	    // Null user.
	    System.err.println("NULL User deletion");

	    User user = tag.findUser("");
	    if (user != null) {
		tag.deleteUser(user);
		System.err.println("EMPTY user deleted");
	    } else {
		user = tag.findUser(null);
		if (user != null) {
		    tag.deleteUser(user);
		    System.err.println("NULL user deleted");
		} else {
		    System.err.println("NULL user was not deleted");
		}
	    } 	    
	} else {
	    // Named user.
	    System.err.println("NAMED User deletion");

	    User user = tag.findUser(uname);
	    if (user != null) {
		tag.deleteUser(user);
		System.err.println("NAMED user deleted");
	    } else {
		System.err.println("NAMED user was not deleted");
	    }
	}
	
    }


    /** Action: SHOW_USERS. Displays information about users.
     * Param: path The Tag's full path (ex. /root/T1).
     */
    public void listUsersAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	String tagPathName = params.getProperty("path");
	if (tagPathName == null) 
	    throw new IllegalArgumentException("No Tag specified");
    
	Path tagPath = new Path("/"+dbRootName, tagPathName);

	Tag tag = OSS_Utilities.fetchTag(tagPath);

	if (tag == null)
	     throw new IllegalArgumentException("No such Tag ["+tagPathName+"] found.");

	Iterator it = tag.listAllUsers();
	 
	 System.err.print("[");
	 while (it.hasNext()) {
	     User user= (User)it.next();
	     System.out.println("Found User: "+user.getFullPath()+
				"\n\t"+user.getFname()+" "+user.getSname()+
				"\n\t"+user.getOrganization()+"."+
				"\n\t"+user.getAddress1()+","+
				"\n\t"+user.getAddress2()+","+
				"\n\t"+user.getAddress3()+","+
				"\n\t"+user.getCountry()+
				"\n\tEmail: "+user.getEmail());
	      System.err.print("["+user.getName()+"] :");
	      if (user.getName() == null)
		  System.err.print("[NULL]");

	 }	    
	 
	 

    }
    
    /** Action: LIST_PROPOSALS. Lists available PI Proposals.
      *
      */
    public void listProposalsAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String userPathName = params.getProperty("path");
	if (userPathName == null)
	    throw new IllegalArgumentException("No User specified");
	
	Path userPath = new Path("/"+dbRootName, userPathName);
	User user     = OSS_Utilities.fetchUser(userPath);
	
	if (user == null)
	    throw new IllegalArgumentException("No such User ["+userPathName+"] found");
	
	System.err.print("[");
	Iterator it = user.listAllProposals();
	while (it.hasNext()) {
	    KVPair pair = (KVPair)it.next();
	    String name = (String)pair.getKey();
	    
	    Proposal proposal = OSS_Utilities.fetchProposal(new Path(userPath.toString(),name));
	    if (proposal != null) { 	 	    
		System.err.print(proposal.getName()+":");	
	    }	   
	}
	System.err.println("]");
    }
    
    /** Action: LIST_COI_PROPOSALS. Lists available CoI Proposals.
      *
      */
    public void listCoIProposalsAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String userPathName = params.getProperty("path");
	if (userPathName == null)
	    throw new IllegalArgumentException("No User specified");
	
	Path userPath = new Path("/"+dbRootName, userPathName);
	User user     = OSS_Utilities.fetchUser(userPath);
	
	if (user == null)
	    throw new IllegalArgumentException("No such User ["+userPathName+"] found");
	
	System.err.println("LISTCOI:: coip has now: "+user.getCoIProposals().size()+" entrys");
	
	System.err.print("[");
	Iterator it = user.listAllCoIProposals();
	while (it.hasNext()) {
	    KVPair pair = (KVPair)it.next();
	    String name = (String)pair.getKey();
	
	    System.err.println("LISTCOI:: coip was: "+name);
    
	    Proposal proposal = OSS_Utilities.fetchProposal(new Path(name));
	    if (proposal != null) { 	 	    
		System.err.print(proposal.getName()+":");	
	    } else {
		System.err.print("no-proposal");
	    }	   
	}
	System.err.println("]");
    }
    
    /** Action: ADD_PROPOSAL. Adds a Proposal.
     *
     */
    public void addProposalAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String userPathName = params.getProperty("path");
	if (userPathName == null)
	    throw new IllegalArgumentException("No User specified");

	Path userPath = new Path("/"+dbRootName, userPathName);
	User user     = OSS_Utilities.fetchUser(userPath);
	
	if (user == null)
	    throw new IllegalArgumentException("No such User ["+userPathName+"] found");
	
	String propName = params.getProperty("name");
	if (propName == null) 
	    throw new IllegalArgumentException("No Proposal name specified");
	
	Proposal proposal = new Proposal(propName);

	float  alloc = params.getFloatValue("total", 0.0f);
	
	double fixed = params.getDoubleValue("fixed", 0.0);

	boolean free = (params.getProperty("free") != null);
	
	String pust  = params.getProperty("pust");
	String sci   = params.getProperty("science");

	float allocBP = params.getFloatValue("allocBP", 0.0f);
	float allocBA = params.getFloatValue("allocBA", 0.0f);
	float allocBX = params.getFloatValue("allocBX", 0.0f);
	
	float allocDP = params.getFloatValue("allocDP", 0.0f);
	float allocDA = params.getFloatValue("allocDA", 0.0f);
	float allocDX = params.getFloatValue("allocDX", 0.0f);
	
	int priority  = params.getIntValue("priority", -1);

	String strActivation = params.getProperty("activation");
	if (strActivation == null)
	    throw new IllegalArgumentException("Activation date not specified");
	Date activation = null;
	try {
	    activation = pdf.parse(strActivation);
	} catch (ParseException px) {
	    throw new IllegalArgumentException("Failed to parse activation date: "+px);
	}
	String strExpiry     = params.getProperty("expiry");
	if (strExpiry == null)
	    throw new IllegalArgumentException("Expiry date not specified");
	Date expiry = null;
	try {
	    expiry = pdf.parse(strExpiry);
	} catch (ParseException px) {
	    throw new IllegalArgumentException("Failed to parse expiry date: "+px);
	}

	// Instruments allowed.
	String insts = params.getProperty("inst", "");
	StringTokenizer t = new StringTokenizer(insts, ":");
	String iid = null;
	while (t.hasMoreTokens()) {
	    iid = t.nextToken();
	    proposal.setXInstrumentsAllowed(iid, true);
	    System.err.println("Adding instrument: "+iid);
	}

	proposal.setAllocatedTime(alloc);
	proposal.setAllocatedFixedFraction(fixed);
       
	proposal.setPustAbstract(pust);
	proposal.setScienceAbstract(sci);

	proposal.setActivationDate(activation.getTime());
	proposal.setExpiryDate(expiry.getTime());
	
	proposal.setAllocatedFraction(Proposal.BRIGHT, Proposal.POOR,      allocBP);
	proposal.setAllocatedFraction(Proposal.BRIGHT, Proposal.AVERAGE,   allocBA);
	proposal.setAllocatedFraction(Proposal.BRIGHT, Proposal.EXCELLENT, allocBX);
	proposal.setAllocatedFraction(Proposal.DARK,   Proposal.POOR,      allocDP);
	proposal.setAllocatedFraction(Proposal.DARK,   Proposal.AVERAGE,   allocDA);
	proposal.setAllocatedFraction(Proposal.DARK,   Proposal.EXCELLENT, allocDX);
	
	proposal.setPriority(priority);

	// Set RCS ID etc.
	long now = System.currentTimeMillis();
	proposal.setLastUnLocked(now);
	proposal.setLastEditor(ADMIN_USER);
	proposal.setLastRegId(ADMIN_REG);
	proposal.setLock(0);
	proposal.addRevisionInfo(now, ADMIN_USER, ADMIN_REG, STUB_COMMENT);

	// set to use RATCAM (old method only)
	proposal.setInstrumentsAllowed(1);

	user.addProposal(propName);

	proposal.setPath(user.getFullPath());
	
	OSS_Utilities.storeProposal(proposal);
	
    }
    
    /** Action SHOW_PROPOSAL. Displays a Proposal in XML to stderr.
     * Param: path The Proposal full path (ex root).
     *
     */
    public void showProposalAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	String proposalPathName = params.getProperty("path");
	if (proposalPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");

	String format = params.getProperty("format", "report");
	
	Path proposalPath = new Path("/"+dbRootName, proposalPathName);
	

	Proposal proposal = null;

	System.err.println("DB::Search for proposal: "+proposalPath);

	try {
	    proposal = OSS_Utilities.fetchProposal(proposalPath);
	    
	} catch (Exception e) {

	    System.err.println("DB::While reading proposal: "+e);
	}

	System.err.println("DB::Located Prop: "+proposal);


	if (format.equals("html")) {

	    try {
		String result = proposal.toHtmlString(0);
		
		System.err.println(result);
	    } catch (Exception e) {

		e.printStackTrace();

	    }
	} else if
	    (format.equals("report")) {

	    printProposal(proposal);
	    
	}
    }

    /** Action CLEAR_PROPOSAL. Removes ALL content from a Proposal.
     * Param: path The Proposal full path (ex root).
     *
     */
    public void clearProposalAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String proposalPathName = params.getProperty("path");
	if (proposalPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path proposalPath = new Path("/"+dbRootName, proposalPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(proposalPath);
	
	proposal.removeAllSources();
	proposal.removeAllInstrumentConfigs();
	proposal.removeAllTelescopeConfigs();
	proposal.removeAllPipelineConfigs();
	proposal.removeAllGroups();

	OSS_Utilities.storeProposal(proposal);
    }


    /** Action CLEAR_REVISIONS. Removes ALL revisions from a Proposal.
     * Param: path The Proposal full path (ex root).
     *
     */
    public void clearRevisionsAction(ConfigurationProperties params)	
	throws IllegalArgumentException, IOException {
	
	String proposalPathName = params.getProperty("path");
	if (proposalPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path proposalPath = new Path("/"+dbRootName, proposalPathName);

	System.err.println("DB:Search proposal: " +proposalPathName);

	Proposal proposal= null;

	try {
	    proposal = OSS_Utilities.fetchProposal(proposalPath);
	} catch (Exception e) {
	    System.err.println("DB:While reading prop: "+proposalPath+ " : "+e);
	}

	System.err.println("DB:Got prop:"+proposal);

	try {
	    proposal.clearRevisions();	    
	    proposal.getName();
	} catch (Exception e) {
	    System.err.println("DB:A starnge thing occurred: "+e); 
	}

	System.err.println("DB:Prop: Revs:"+proposal.getRevisions());
	System.err.println("");

	System.err.println("DB:Storing prop");

	OSS_Utilities.storeProposal(proposal);

	System.err.println("DB:Done storing");
	
    }
    
    /** Action ADD_REVISION. Adds a revision to a Proposal.
     * Param: path The Proposal full path (ex root).
     *
     */
    public void addRevisionAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
		
	String proposalPathName = params.getProperty("path");
	if (proposalPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path proposalPath = new Path("/"+dbRootName, proposalPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(proposalPath);
	
	String comment = params.getProperty("comment");
	
	long now = System.currentTimeMillis();
    
	proposal.addRevisionInfo(now, ADMIN_USER, ADMIN_REG, comment);
   	
	OSS_Utilities.storeProposal(proposal);
    }


    /** Action UNLOCK_PROPOSAL. Unlocks a locked Proposal.
     * Param: path The Proposal full path (ex root).
     *
     */
    public void unlockProposalAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	String proposalPathName = params.getProperty("path");
	if (proposalPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path     proposalPath = new Path("/"+dbRootName, proposalPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(proposalPath);
	
	String comment = params.getProperty("comment");
	
	long now = System.currentTimeMillis();

	proposal.addRevisionInfo(now, ADMIN_USER, ADMIN_REG, comment);

	proposal.forceUnLock();	
	proposal.setLastUnLocked(now);
	proposal.setLastEditor(ADMIN_USER);
	proposal.setLastRegId(ADMIN_REG);
	proposal.setAdmin(false);

	OSS_Utilities.storeProposal(proposal);
    }

     /** Action LOCK_PROPOSAL. Locks a Proposal as ADMIN user.
     * Param: path The Proposal full path (ex root).
     *
     */
    public void lockProposalAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	String proposalPathName = params.getProperty("path");
	if (proposalPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");

	int    lock   = params.getIntValue("lock", ADMIN_LOCK);
	
	String editor = params.getProperty("editor", ADMIN_USER);
	
	long   regId  = params.getLongValue("reg", ADMIN_REG);
	
	Path   proposalPath = new Path("/"+dbRootName, proposalPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(proposalPath);
	
	proposal.lock(lock);	
	proposal.setLastLocked(System.currentTimeMillis());
	proposal.setLastEditor(editor);
	proposal.setLastRegId(regId);
	proposal.setAdmin(true);
	proposal.setLock(lock);
	
	OSS_Utilities.storeProposal(proposal);
    }

    
    /** Action: LIST_ALL_USERS.
     */
    public void listAllUsersAction(ConfigurationProperties params)
	throws IllegalArgumentException, IOException {
	
	Root root = OSS_Utilities.fetchRoot();
	
	// Check it exists.
	if (root == null) {		
	   throw new IllegalArgumentException("Root not found");
	} 
	
	Iterator iTag = root.listAllTags();
	while (iTag.hasNext()) {
	    
	    Tag tag = (Tag)iTag.next();
	    
	    System.err.println("Tag located: "+tag.getFullPath());
	    
	    Iterator iUser = tag.listAllUsers();
	    while (iUser.hasNext()) {
		
		User user = (User)iUser.next();
		
		System.err.println("User located: "+user.getFullPath()+" : "+user.getPassword());
		
	    }
	}
    }
    

    /** Action: ADD_GROUP. Adds a group to a proposal.
     */
    public void addGroupAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String proposalPathName = params.getProperty("path");
	if (proposalPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path proposalPath = new Path("/"+dbRootName, proposalPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(proposalPath);
	
	if (proposal == null) 
	    throw new IllegalArgumentException("No such Proposal ["+proposalPathName+"] found");

	String groupName = params.getProperty("name");
	if (groupName == null) 
	    throw new IllegalArgumentException("No Group name specified");
	
	String strType = params.getProperty("type", "flexible");

	Group group = null;
	if (strType.equals("flexible")) {	    
	    group = new Group(groupName);

	} else if
	    (strType.equals("fixed")) {
	    group = new FixedGroup(groupName);	
	} else if
	    (strType.equals("monitor")) {
	    group = new MonitorGroup(groupName);

	} else if
	    (strType.equals("ephemeris")) {
	    group = new EphemerisGroup(groupName);

	} else if
	    (strType.equals("repeatable")) {
	    group = new RepeatableGroup(groupName);

	} else
	    throw new IllegalArgumentException("Unknown Group type: "+strType);

	// --------------------
	// Group Common fields.
	// --------------------
	String strExpiry = params.getProperty("expiry");
	if (strExpiry == null)
	    throw new IllegalArgumentException("Expiry date not specified");
	Date expiry = null;
	try {
	    expiry = pdf.parse(strExpiry);
	} catch (ParseException px) {
	    throw new IllegalArgumentException("Failed to parse expiry date: "+px);
	}
	
	String strLunar = params.getProperty("lunar", "BRIGHT");
	int lunar = Proposal.BRIGHT;
	if (strLunar.equals("BRIGHT"))
	    lunar = Proposal.BRIGHT;
	else if
	    (strLunar.equals("DARK"))
	    lunar = Proposal.DARK;
	else 
	    throw new IllegalArgumentException("Illegal value for minimum lunar: "+strLunar);
	
	String strSeeing = params.getProperty("seeing", "POOR");
	int seeing = Proposal.POOR;
	if (strSeeing.equals("POOR"))
	    seeing = Proposal.POOR;
	else if
	    (strSeeing.equals("AVERAGE"))
	    seeing = Proposal.AVERAGE;
	else if
	    (strSeeing.equals("EXCELLENT"))
	    seeing = Proposal.EXCELLENT;
	else 
	    throw new IllegalArgumentException("Illegal value for minimum seeing: "+strSeeing);
	
	double meridian = params.getDoubleValue("meridian-limit", 0.0);


	String strTwilight = params.getProperty("twilight", "OPTIONAL");
	int twilight = Group.TWILIGHT_USAGE_OPTIONAL;
	if (strTwilight.equals("NEVER"))
	    twilight = Group.TWILIGHT_USAGE_NEVER;
	else if
	    (strTwilight.equals("OPTIONAL"))
	    twilight = Group.TWILIGHT_USAGE_OPTIONAL;
	else if
	    (strTwilight.equals("ALWAYS"))
	    twilight = Group.TWILIGHT_USAGE_ALWAYS;
	else 
	    throw new IllegalArgumentException("Illegal value for twilight mode: "+strTwilight);

	boolean photom = params.getBooleanValue("photom", false);

	boolean notify = params.getBooleanValue("notify", false);
	
	int priority = params.getIntValue("priority", 0);

	group.setExpiryDate(expiry.getTime());
	group.setMinimumLunar(lunar);
	group.setMinimumSeeing(seeing);
	group.setNotifyWhenDone(notify);
	group.setMeridianLimit(meridian);
	group.setTwilightUsageMode(twilight);
	group.setPhotometric(photom);
	group.setPriority(priority);

	if
	    (strType.equals("fixed")) {
	    // ---------------------------
	    // FixedGroup specific fields.
	    // ---------------------------
	    FixedGroup fGroup = (FixedGroup)group;
	    
	    String strTime = params.getProperty("fixed-time");
	    if (strTime == null)
		throw new IllegalArgumentException("Fixed date not specified");
	    Date fixedTime = null;
	    try {
		fixedTime = pdf.parse(strTime);
	    } catch (ParseException px) {
		throw new IllegalArgumentException("Failed to parse fixed date: "+px);
	    }
	    fGroup.setFixedTime(fixedTime.getTime());
	} else if
	    (strType.equals("monitor")) {
	    // ---------------------------
	    // MonitorGroup specific fields.
	    // --------------------------
	    MonitorGroup monGroup = (MonitorGroup)group;
	    
	    String strStart = params.getProperty("start-date");
	    if (strStart == null)
		throw new IllegalArgumentException("Start date not specified");
	    Date startDate = null;
	    try {
		startDate = pdf.parse(strStart);
	    } catch (ParseException px) {
		throw new IllegalArgumentException("Failed to parse start date: "+px);
	    }
	    monGroup.setStartDate(startDate.getTime());
	    
	    String strEnd = params.getProperty("end-date");
	    if (strEnd == null)
		throw new IllegalArgumentException("End date not specified");
	    Date endDate = null;
	    try {
		endDate = pdf.parse(strEnd);
	    } catch (ParseException px) {
		throw new IllegalArgumentException("Failed to parse end date: "+px);
	    }
	    monGroup.setEndDate(endDate.getTime());
	    
	    try {
		int phours = params.getIntValue("period");
		//long period = params.getLongValue("period");
		long period = (long)phours*3600000L;
		monGroup.setPeriod(period);
	    } catch (ParseException px) {
		throw new  IllegalArgumentException("Failed to parse period: "+px);
	    }
	    
	    try {
		float fraction = params.getFloatValue("float");
		monGroup.setFloatFraction(fraction);
	    } catch (ParseException px) {
		throw new  IllegalArgumentException("Failed to parse float fraction: "+px);
	    }
	} else if
	    (strType.equals("ephemeris")) {
	    // ---------------------------
	    // EphemerisGroup specific fields.
	    // --------------------------
	    EphemerisGroup ephGroup = (EphemerisGroup)group;
	    
	    String strStart = params.getProperty("start");
	    if (strStart == null)
		throw new IllegalArgumentException("Start date not specified");		
	    Date startDate = null;
	    try {
		startDate = pdf.parse(strStart); 
		ephGroup.setStart(startDate.getTime());
	    } catch (ParseException px) {
		throw new IllegalArgumentException("Failed to parse start date: "+px);
	    }
	    
	    try {
		long period = params.getLongValue("period");
		ephGroup.setPeriod(period);
	    } catch (ParseException px) {
		throw new IllegalArgumentException("Failed to parse period: "+px);
	    }  
	    
	    try {
		float phase = params.getFloatValue("phase");
		ephGroup.setPhase(phase);
	    } catch (ParseException px) {
		throw new IllegalArgumentException("Failed to parse phase: "+px);
	    }  
	} else if
	    (strType.equals("repeatable")) {
	    // --------------------------------
	    // RepeatableGroup specific fields.
	    // --------------------------------
	    RepeatableGroup repGroup = (RepeatableGroup)group;
	    
	    String strStart = params.getProperty("start-date");
	    if (strStart == null)
		throw new IllegalArgumentException("Start date not specified");
	    Date startDate = null;
	    try {
		startDate = pdf.parse(strStart);
	    } catch (ParseException px) {
		throw new IllegalArgumentException("Failed to parse start date: "+px);
	    }
	    repGroup.setStartDate(startDate.getTime());
	    
	    String strEnd = params.getProperty("end-date");
	    if (strEnd == null)
		throw new IllegalArgumentException("End date not specified");
	    Date endDate = null;
	    try {
		endDate = pdf.parse(strEnd);
	    } catch (ParseException px) {
		throw new IllegalArgumentException("Failed to parse end date: "+px);
	    }
	    repGroup.setEndDate(endDate.getTime());
	    
	    try {
		long minimumInterval = params.getLongValue("min-interval");
		repGroup.setMinimumInterval(minimumInterval);
	    } catch (ParseException px) {
		throw new IllegalArgumentException("Failed to parse min-interval: "+px);
	    }
	    
	    try {
		int maximumRepeats = params.getIntValue("max-repeats");
		repGroup.setMaximumRepeats(maximumRepeats);
	    } catch (ParseException px) {
		throw new IllegalArgumentException("Failed to parse max-repeats: "+px);
	    }
	}

	Scheduling.calculateExecutionTimes(group);

	proposal.addGroup(group);

	OSS_Utilities.storeProposal(proposal);
	
    }
    
    /** Action: ADD_INST_CFG. Adds an instrument config.
     */
    public void addInstConfigAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	String proposalPathName = params.getProperty("path");
	if (proposalPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path proposalPath = new Path("/"+dbRootName, proposalPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(proposalPath);
	
	if (proposal == null) 
	    throw new IllegalArgumentException("No such Proposal ["+proposalPathName+"] found");

	String icName = params.getProperty("name");
	if (icName == null) 
	    throw new IllegalArgumentException("No InstConfig  name specified");
	
	String strInst = params.getProperty("inst", "RATCAM");

	InstrumentConfig config = null;

	if (strInst.equals("RATCAM")) {	    
	   
	    config = new RATCamConfig(icName);

	    String lfilter = params.getProperty("lowerfilter", "clear");
	    String ufilter = params.getProperty("upperfilter", "clear");
	    
	    int bin = params.getIntValue("binning", 1);
	    
	    ((CCDConfig)config).setLowerFilterWheel(lfilter);
	    ((CCDConfig)config).setUpperFilterWheel(ufilter);
	    CCDDetector detector = (CCDDetector) config.getDetector(0);
	    
	    detector.clearAllWindows();
	    detector.setXBin(bin);
	    detector.setYBin(bin);
	} else if
	    (strInst.equals("NUVSPEC")) {
	    
	    config = new LowResSpecConfig(icName);
	    
	    double wave = params.getDoubleValue("wavelength",0.0);
	     
	    int bin = params.getIntValue("binning", 1);
	    
	    ((LowResSpecConfig)config).setWavelength(wave);
	    LowResSpecDetector detector = (LowResSpecDetector) config.getDetector(0);
	    
	    detector.clearAllWindows();
	    detector.setXBin(bin);
	    detector.setYBin(bin);
	    
	}else if
	    (strInst.equals("MESSPEC")) {

	    config = new HiResSpecConfig(icName);
	    
	    String fslide = params.getProperty("filter-slide");
	    
	    if (fslide == null)
		throw new IllegalArgumentException("No filter-slide specified");
	    
	    ((HiResSpecConfig)config).setFilterSlideName(fslide);
	     
	    int bin = params.getIntValue("binning", 1);
	    
	    HiResSpecDetector detector = (HiResSpecDetector) config.getDetector(0);
	    
	    detector.clearAllWindows();
	    detector.setXBin(bin);
	    detector.setYBin(bin);
	    
	}else if
	    (strInst.equals("SUPIRCAM")) {
	    
	    config = new IRCamConfig(icName);

	    String filter = params.getProperty("filter", "blank");
	   
	    int bin = params.getIntValue("binning", 1);
	    
	    ((IRCamConfig)config).setFilterWheel(filter);
	  
	    IRCamDetector detector = (IRCamDetector) config.getDetector(0);
	    
	    detector.clearAllWindows();
	    detector.setXBin(bin);
	    detector.setYBin(bin);

	}

	proposal.addInstrumentConfig(config);

	System.err.println("Added Instrument config: "+config);

	OSS_Utilities.storeProposal(proposal);
	
    }

    /** Action: ADD_TEL_CFG. Adds a telescope config.
     */
    public void addTeleConfigAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	String proposalPathName = params.getProperty("path");
	if (proposalPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path proposalPath = new Path("/"+dbRootName, proposalPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(proposalPath);
	
	if (proposal == null) 
	    throw new IllegalArgumentException("No such Proposal ["+proposalPathName+"] found");

	String tcName = params.getProperty("name");
	if (tcName == null) 
	    throw new IllegalArgumentException("No TeleConfig  name specified");

	TelescopeConfig config = new TelescopeConfig(tcName);

	float focus = params.getFloatValue("focus", 0.0f);
	config.setFocusOffset(focus);

	String strAgUseMode = params.getProperty("agusemode", "OPTIONAL");	
	if (strAgUseMode.equals("NEVER")) 
	    config.setAutoGuiderUsageMode(TelescopeConfig.AGMODE_NEVER);
	else if
	    (strAgUseMode.equals("OPTIONAL"))
	    config.setAutoGuiderUsageMode(TelescopeConfig.AGMODE_OPTIONAL);
	else if
	    (strAgUseMode.equals("MANDATORY"))
	    config.setAutoGuiderUsageMode(TelescopeConfig.AGMODE_MANDATORY);
	
	int    agParam1     = params.getIntValue("agparam1", 0);
	int    agParam2     = params.getIntValue("agparam2", 0);

	String strAgAquire  = params.getProperty("agaquiremode", "RANK");	
	if (strAgAquire.equals("RANK")) {
	    config.setAutoGuiderStarSelectionMode(TelescopeConfig.STAR_SELECTION_RANK);	
	    config.setAutoGuiderStarSelection1(agParam1);
	} else if
	    (strAgAquire.equals("RANGE")) {
	    config.setAutoGuiderStarSelectionMode(TelescopeConfig.STAR_SELECTION_RANGE);
	    config.setAutoGuiderStarSelection1(agParam1);
	    config.setAutoGuiderStarSelection2(agParam2);
	} else if
	    (strAgAquire.equals("PIXEL")) {
	    config.setAutoGuiderStarSelectionMode(TelescopeConfig.STAR_SELECTION_PIXEL);
	    config.setAutoGuiderStarSelection1(agParam1);
	    config.setAutoGuiderStarSelection2(agParam2);
	 }

	String strRotMode   = params.getProperty("rotmode", "SKY");
		
	if (strRotMode.equals("SKY")) {
	    config.setRotatorAngleMode(TelescopeConfig.ROTATOR_MODE_SKY);
	} else if 
	    (strRotMode.equals("MOUNT")) {
	    config.setRotatorAngleMode(TelescopeConfig.ROTATOR_MODE_MOUNT);
	} else if 
	    (strRotMode.equals("VERTICAL")) {
	    config.setUseParallacticAngle(true);	    
	}

	double rotate= params.getDoubleValue("rotatorangle", 0.0);
	config.setSkyAngle(rotate);

	proposal.addTelescopeConfig(config);

	OSS_Utilities.storeProposal(proposal);
	
    }
    
    /** Action: ADD_SOURCE. Adds a source.
     */
    public void addSourceAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	String proposalPathName = params.getProperty("path");
	if (proposalPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path proposalPath = new Path("/"+dbRootName, proposalPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(proposalPath);
	
	if (proposal == null) 
	    throw new IllegalArgumentException("No such Proposal ["+proposalPathName+"] found");
	
	String srcName = params.getProperty("name");
	if (srcName == null) 
	    throw new IllegalArgumentException("No Source name specified");
	
	ExtraSolarSource source  = new ExtraSolarSource(srcName);
	
	String strFrame = params.getProperty("frame", "FK5");
	if (strFrame.equals("FK4"))
	    source.setFrame(Source.FK4);
	else if
	    (strFrame.equals("FK5"))
	    source.setFrame(Source.FK5);

	float epoch = params.getFloatValue("epoch", 2000.0f);
	source.setEpoch(epoch);
	
	String strEquinox = params.getProperty("equinox", "J2000.0");
	char eql = strEquinox.charAt(0);
	source.setEquinoxLetter(eql);
	
	String strEq = strEquinox.substring(1);
	try {
	    float equinox = Float.parseFloat(strEq);	
	    source.setEquinox(equinox);
	} catch (NumberFormatException nx) {
	    throw new IllegalArgumentException("Failed to parse equinox: ["+strEquinox+"]");
	}
	
	String strRA = params.getProperty("ra");	
	try {
	    double ra = Position.parseHMS(strRA, ":");
	    source.setRA(ra);
	} catch (ParseException px) {
	     throw new IllegalArgumentException("Failed to parse RA: ["+strRA+"]");
	}

	String strDec = params.getProperty("dec");	
	try {
	    double dec = Position.parseDMS(strDec, ":");
	    source.setDec(dec);
	} catch (ParseException px) {
	    throw new IllegalArgumentException("Failed to parse Dec: ["+strDec+"]");
	}
	
	try {
	    double pmRA = params.getDoubleValue("pmra");
	    source.setPmRA(pmRA);
	} catch (ParseException px) {
	    throw new IllegalArgumentException("Failed to parse pmra: "+px);
	}
	
	try {
	    double pmDec = params.getDoubleValue("pmdec");
	    source.setPmDec(pmDec);
	} catch (ParseException px) {
	    throw new IllegalArgumentException("Failed to parse pmdec: "+px);
	}
	
	try {
	    double parallax = params.getDoubleValue("parallax");
	    source.setParallax(parallax);
	} catch (ParseException px) {
	    throw new IllegalArgumentException("Failed to parse parallax: "+px);
	}
	
	try {
	    double rv = params.getDoubleValue("rv");
	    source.setRadialVelocity(rv);
	} catch (ParseException px) {
	    throw new IllegalArgumentException("Failed to parse rv: "+px);
	}
	
	proposal.addSource(source);
	
	OSS_Utilities.storeProposal(proposal);
	
	System.err.println("Added source: "+source);

    }

	
    /** Action: ADD_OBS. Adds an Observation to a Group.
     */
    public void addObservationAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String groupPathName = params.getProperty("path");
	if (groupPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path groupPath = new Path("/"+dbRootName, groupPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(groupPath);
	
	if (proposal == null) 
	    throw new IllegalArgumentException("No such Proposal ["+groupPathName+"] found");
	
	String groupName = groupPath.getGroupByName();

	Group group = proposal.findGroup(groupName);
	
	if (group == null)
	    throw new IllegalArgumentException("No such Group ["+groupPathName+"] found");
		
	
	String obsName = params.getProperty("name");
	
	if (obsName == null) 
	    throw new IllegalArgumentException("No Observation name specified");
	
	Observation obs = new Observation(obsName);

	String srcId = params.getProperty("src-id");
	if (srcId == null)
	     throw new IllegalArgumentException("No name specified");

	Source src = proposal.findSource(srcId);
	if (src == null) 
	     throw new IllegalArgumentException("Source ["+srcId+"] not found in proposal ["+
						proposal.getName()+"]");
	obs.setSource(src);

	String icId = params.getProperty("ic-id");
	if (icId == null)
	     throw new IllegalArgumentException("No name specified");

	InstrumentConfig ic = proposal.findInstrumentConfig(icId);
	if (ic == null) 
	     throw new IllegalArgumentException("InstConfig ["+icId+"] not found in proposal ["+
						proposal.getName()+"]");
	obs.setInstrumentConfig(ic);
	
	String tcId = params.getProperty("tc-id");
	if (tcId == null)
	     throw new IllegalArgumentException("No name specified");

	TelescopeConfig tc = proposal.findTelescopeConfig(tcId);
	if (tc == null) 
	     throw new IllegalArgumentException("TeleConfig ["+tcId+"] not found in proposal ["+
						proposal.getName()+"]");
	obs.setTelescopeConfig(tc);

	float expose = params.getFloatValue("exposure", 0.0f);
	obs.setExposeTime(expose);

	int multrun = params.getIntValue("multrun", 1);
	obs.setNumRuns(multrun);

	boolean conditional = (params.getProperty("conditional") != null);
	obs.setConditionalExposure(conditional);


	Mosaic mosaic = new Mosaic();

	String strMosaic = params.getProperty("mosaic-pattern", "SINGLE");
	if (strMosaic.equals("CROSS"))
	    mosaic.setPattern(Mosaic.CROSS);
	else if
	    (strMosaic.equals("ARRAY"))
	    mosaic.setPattern(Mosaic.ARRAY);
	else
	     mosaic.setPattern(Mosaic.SINGLE);
	
	double mosRAOffset = params.getDoubleValue("mosaic-ra-off", 0.0);
	mosaic.setOffsetRA(mosRAOffset);
	double mosDecOffset = params.getDoubleValue("mosaic-dec-off", 0.0);
	mosaic.setOffsetDec(mosDecOffset);

	int mosRACells = params.getIntValue("mosaic-ra-cells", 1);
	mosaic.setCellsRA(mosRACells);
	int mosDecCells = params.getIntValue("mosaic-dec-cells", 1);
	mosaic.setCellsDec(mosDecCells);
	
	boolean scale = (params.getProperty("mosaic-scale") != null);
	mosaic.setScaleToPixel(scale);

	obs.setMosaic(mosaic);

	double offRA = params.getDoubleValue("src-ra-off", 0.0);
	obs.setSourceOffsetRA(offRA);

	double offDec = params.getDoubleValue("src-dec-off", 0.0);
	obs.setSourceOffsetDec(offDec);

	group.addObservation(obs);

	// Dont forget to re-calculate this !
	Scheduling.calculateExecutionTimes(group);

	OSS_Utilities.storeProposal(proposal);
	
	System.err.println("Added obs: "+obs);

    }


    /** Action: SHOW_OBS. Displays details of an Observation.
     */
    public void showObservationAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String obsPathName = params.getProperty("path");
	if (obsPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path obsPath = new Path("/"+dbRootName, obsPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(obsPath);
	
	if (proposal == null) 
	    throw new IllegalArgumentException("No such Proposal ["+obsPathName+"] found");

	String groupName = obsPath.getGroupByName();

	Group group = proposal.findGroup(groupName);
	
	if (group == null)
	    throw new IllegalArgumentException("No such Group ["+groupName+"] found");

	String obsName = obsPath.getObservationByName();

	Observation obs = group.findObservation(obsName);

	if (obs == null)
	    throw new IllegalArgumentException("No such Observation ["+obsName+"] found");

	String result = obs.toHtmlString(0);
	
	System.err.println(result);

    }

    /** Action: CHECK_GROUP. Displays the Group's doneness in a Proposal.
     */
    public void checkGroupAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String groupPathName = params.getProperty("path");
	if (groupPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path groupPath = new Path("/"+dbRootName, groupPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(groupPath);
	
	if (proposal == null) 
	    throw new IllegalArgumentException("No such Proposal ["+groupPathName+"] found");

	String groupName = groupPath.getGroupByName();

	Group group = proposal.findGroup(groupName);
	
	if (group == null)
	    throw new IllegalArgumentException("No such Group ["+groupPathName+"] found");
		
	java.util.List events = group.getHistory();

	System.err.println("Group: "+group.getFullPath());
	Iterator it = events.iterator();
	while (it.hasNext()) {
	    Group.History history = (Group.History)it.next();
	    System.err.println("\n"+sdf.format(new Date(history.getDate()))+
			       (history.getDone() ? " Done: " : " Not done: ")+
			       history.getDetails());	
	}
    }


     /** Action: UPDATE_GROUP. Ads an event detail to the Group's history.
      */
    public void updateGroupAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String groupPathName = params.getProperty("path");
	if (groupPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path groupPath = new Path("/"+dbRootName, groupPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(groupPath);
	
	if (proposal == null) 
	    throw new IllegalArgumentException("No such Proposal ["+groupPathName+"] found");

	String groupName = groupPath.getGroupByName();

	Group group = proposal.findGroup(groupName);
	
	if (group == null)
	    throw new IllegalArgumentException("No such Group ["+groupPathName+"] found");
				
	String strDate= params.getProperty("date");
	if (strDate == null)
	    throw new IllegalArgumentException("Event date not specified");
	Date date = null;
	try {
	    date = pdf.parse(strDate);
	} catch (ParseException px) {
	    throw new IllegalArgumentException("Failed to parse event date: "+px);
	}

	boolean done = params.getBooleanValue("done", false);	

	String detail = params.getProperty("detail", "Not available");

	group.updateHistory(date.getTime(), done, detail);
	
	OSS_Utilities.storeProposal(proposal);
	
    }
    
    /** Action: SHOW_GROUP. Shows details of a Group
      */
    public void showGroupAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	
	String groupPathName = params.getProperty("path");
	if (groupPathName == null) 
	    throw new IllegalArgumentException("No proposal specified");
	
	Path groupPath = new Path("/"+dbRootName, groupPathName);
	
	Proposal proposal = OSS_Utilities.fetchProposal(groupPath);
	
	if (proposal == null) 
	    throw new IllegalArgumentException("No such Proposal ["+groupPathName+"] found");

	String groupName = groupPath.getGroupByName();

	Group group = proposal.findGroup(groupName);
	
	if (group == null)
	    throw new IllegalArgumentException("No such Group ["+groupPathName+"] found");
					
	String result = group.toHtmlString(0);
	
	System.err.println(result);
	
    }


    /** Action: REMOVE_GROUP. Removes a Group from the database.
     */
    public void removeGroupAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {
	System.err.println("*** Not implemented ***");
    }
    
    /** Action: UNLOCK_ALL_PROPOSALS. Unlocks proposals locked by an Editor.
     */
    public void unlockAllProposalsAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {

	long now = System.currentTimeMillis();	

	String comment = "Auto-unlocked by OSS";

	String editor = params.getProperty("lock-editor");
	String eduser = params.getProperty("user", OSS_USER);
	long   regId  = params.getLongValue("reg", OSS_REG);
	boolean  any  = (params.getProperty("any") != null);

	if (editor == null && (! any) )
	    throw new IllegalArgumentException("Unlock-all: No editor specified");

	Root root = OSS_Utilities.fetchRoot();
	
	// Check it exists.
	if (root == null) {		
	    throw new IllegalArgumentException("Root not found");
	} 

	Iterator iTag = root.listAllTags();
	while (iTag.hasNext()) {
	    
	    Tag tag = (Tag)iTag.next();
	    
	    Iterator iUser = tag.listAllUsers();
	    while (iUser.hasNext()) {
		
		User user = (User)iUser.next();
		
		Iterator it = user.listAllProposals();
		while (it.hasNext()) {

		    KVPair pair = (KVPair)it.next();
		    String name = (String)pair.getKey();
		    	
		    System.err.println("Looking for proposal: "+name);
	    
		    Proposal proposal = OSS_Utilities.fetchProposal(new Path(user.getFullPath(), name));
		   
		    if (proposal == null) continue;
		    
		    if (proposal.isLocked() && 
			(proposal.getLastEditor().equals(editor)) ||
			 any) {

			System.err.println("Locked: By: "+proposal.getLastEditor());
			
			//proposal.addRevisionInfo(now, eduser, regId, comment);
			
			proposal.forceUnLock();	
			proposal.setLastUnLocked(now);
			proposal.setLastEditor(eduser);
			proposal.setLastRegId(regId);
			proposal.setAdmin(false);
		    
			OSS_Utilities.storeProposal(proposal);
		    }
		}
	    }
	}
    }

  


    /** Action: SWITCH_ALL_PROPOSALS. Loads and resaves in a new filename.
     */
    public void switchAllProposalsAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {

	long now = System.currentTimeMillis();	

	Root root = OSS_Utilities.fetchRoot();
	
	// Check it exists.
	if (root == null) {		
	    throw new IllegalArgumentException("Root not found");
	} 

	Iterator iTag = root.listAllTags();
	while (iTag.hasNext()) {
	    
	    Tag tag = (Tag)iTag.next();
	    
	    Iterator iUser = tag.listAllUsers();
	    while (iUser.hasNext()) {
		
		User user = (User)iUser.next();
		
		Iterator it = user.listAllProposals();
		while (it.hasNext()) {

		    KVPair pair = (KVPair)it.next();
		    String name = (String)pair.getKey();
		    	
		    System.err.println("Looking for proposal: "+name);
	    
		    Proposal proposal = OSS_Utilities.fetchProposal(new Path(user.getFullPath(), name));
		   
		    if (proposal != null) {
		    
			System.err.println("Proposal: "+proposal.getName());

			proposal.getGroups();

			if (proposal.getRevisions() != null) {
			    Iterator ir = proposal.listRevisions();
			    while (ir.hasNext()) {
				System.err.println("Prop: Revision: ["+(Revision)(ir.next())+"]");
			    }
			}

			//OSS_Utilities.newstoreProposal(proposal);
					       
		    }
		}
	    }
	}
    }


    /** Action: LIST_ALL_TARGETS. Lists all targets in DB.
     */
    public void listAllTargetsAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {

	shutdown = false;

	double lat = params.getDoubleValue("lat", 0.0);
	double lon = params.getDoubleValue("long", 0.0);

	Position.setViewpoint(Math.toRadians(lat), Math.toRadians(lon));
	
	Root root = OSS_Utilities.fetchRoot();
	
	// Check it exists.
	if (root == null) {		
	    throw new IllegalArgumentException("Root not found");
	} 
	
	//SpherePlot sky = new SpherePlot(Math.toRadians(30.), Math.toRadians(40.0));
	
	//JFrame frame = new JFrame("Current Target");
	//frame.getContentPane().add(sky);
	//frame.pack();
	//frame.setSize(200,200);
	//frame.setVisible(true);


	Iterator iTag = root.listAllTags();
	while (iTag.hasNext()) {
	    
	    Tag tag = (Tag)iTag.next();
	    
	    //  System.err.println("\n----------------------------------------\nTag:"+tag.getFullPath()+"\n----------------------------------------");
	    
	    Iterator iUser = tag.listAllUsers();
	    while (iUser.hasNext()) {
		
		User user = (User)iUser.next();
		
		//System.err.println("\n----------------------------------------\nUser"+user.getFullPath()+"\n----------------------------------------");
		
		Iterator it = user.listAllProposals();
		while (it.hasNext()) {
		    KVPair pair = (KVPair)it.next();
		    String name = (String)pair.getKey();
		    
		    //  System.err.println("\n----------------------------------------\nProposal:"+name+"\n----------------------------------------");

		    Proposal proposal = OSS_Utilities.fetchProposal(new Path(user.getFullPath(), name));
		    if (proposal != null) { 	 	    
			Iterator tt = proposal.listAllSources();
			while (tt.hasNext()) {
			    Source source = (Source)tt.next();						    

			    Position target = source.getPosition();

			    String sname = source.getName();
			    while (sname.length() < 16) { sname+=" ";}

			    System.err.println("Target: "+sname+
					       "\t"+Position.formatHMSString(target.getRA(),":")+
					       "\t"+Position.formatDMSString(target.getDec(),":")+
					       "\t Az:  "+Position.toDegrees(target.getAzimuth(),3)+
					       "\t Alt: "+Position.toDegrees(target.getAltitude(), 3)+
					       "\t TH: "+Position.toDegrees(target.getTransitHeight(), 3));

			    //sky.putPoint((float)target.getAltitude(), (float)target.getAzimuth());
					       
			}	   
		    }
		}		
	    }
	}
	
	try {Thread.sleep(30000L);} catch (InterruptedException e) {}
    
    } 

    /** Action: PLOT_SCHEDULE. Plots a graph of group availablity.
     */
    public void plotScheduleAction(ConfigurationProperties params) 
	throws IllegalArgumentException, IOException {

	shutdown = false;
	
	NumberFormat nf = NumberFormat.getInstance();

	long start = System.currentTimeMillis();
	long end = start;

	String strInt = params.getProperty("period", "HOUR");

	double limit = Math.toRadians(params.getDoubleValue("limit", 30.0));
	
	double lat = params.getDoubleValue("lat", 0.0);
	double lon = params.getDoubleValue("long", 0.0);

	Position.setViewpoint(Math.toRadians(lat), Math.toRadians(lon));
	
	long MIN  = 60*1000L;
	long HOUR = 60*MIN;
	long DAY  = 24*HOUR;

	int gp = 1;
	long inc = 0L;
	double tick = 0.0;
	double mtick = 0.0;
	SimpleDateFormat ff = null;
	long window = 0L;
	if (strInt.equals("HOUR")) {
	    gp = 1;
	    window = DAY;
	    tick = (double)60*MIN;
	    mtick = (double)15*MIN;
	    ff = hrf;
	    end = start + DAY;
	    inc = MIN;
	} else if
	    (strInt.equals("DAY")) {
	    gp =2;
	    window = 7*DAY;
	    tick = (double)12*HOUR;
	    mtick = (double)3*HOUR;
	    ff = dayf;
	    end = start + 7*DAY;
	    inc = 15*MIN;
	}
	// Create a Graph in a chart.

	nf.setMaximumFractionDigits(3);
	nf.setMinimumFractionDigits(1);
	
	Chart chart = new Chart();
	chart.setGraphInsets(50, 40, 50, 40);
	chart.setTitle(new TextTitle("Number of Monitoring groups in float period"));
	chart.setGraphBgColor(Color.gray);
	chart.setChartBgColor(Color.black);
	chart.setShowLegend(false);

	Axis xAxis = chart.getXAxis();
	xAxis.setExtent((double)start, (double)end);
	xAxis.setShowMinorTicks(true);
	xAxis.setMajorTickInterval(tick);
	xAxis.setMinorTickInterval(mtick);
	xAxis.setShowMajorGrid(true);
	xAxis.setTitle(new TextTitle("Time"));
	DateFormatter df = new DateFormatter(ff);
	xAxis.setLabeller(new TextLabeller(df));
	xAxis.setGridColor(Color.gray);


	// Setup Y primary axis.
	Axis ypAxis = chart.getYAxisPrimary();
	ypAxis.setExtent(0.0, 50.0);
	ypAxis.setShowMinorTicks(true);
	ypAxis.setShowMajorGrid(true);

	ypAxis.setMajorTickInterval(5.0);
	ypAxis.setMinorTickInterval(1.0);
	ypAxis.setTitle(new TextTitle(""));
	ypAxis.setLabeller(new TextLabeller(new NumberFormatter(nf)));
	ypAxis.setGridColor(Color.yellow);	
	
	// Build the graphs.
	Graph graph = new Graph();
	graph.setLegend("Schedule");
	graph.setPointColor(Color.orange);
	graph.setShowErrorBars(false);
	graph.setPointSize(1);
	graph.setShowJoiningLine(true);
	graph.setAttachedPrimary(true);

	Graph graph2 = new Graph();
	graph2.setLegend("Schedule");
	graph2.setPointColor(Color.cyan);
	graph2.setShowErrorBars(false);
	graph2.setPointSize(1);
	graph2.setShowJoiningLine(true);
	graph2.setAttachedPrimary(true);

	Graph graph3 = new Graph();
	graph3.setLegend("Schedule");
	graph3.setPointColor(Color.blue);
	graph3.setShowErrorBars(false);
	graph3.setPointSize(5);
	graph3.setShowJoiningLine(false);
	graph3.setAttachedPrimary(true);

	Graph graph4 = new Graph();
	graph4.setLegend("Schedule");
	graph4.setPointColor(Color.red);
	graph4.setShowErrorBars(false);
	graph4.setPointSize(1);
	graph4.setShowJoiningLine(false);
	graph4.setAttachedPrimary(true);

	chart.addGraph("Window",  graph);
	chart.addGraph("Visible", graph2);
	chart.addGraph("MLD",     graph3);
	chart.addGraph("Fixed",   graph4);

	JFrame frame = new JFrame("Group availablity schedule from: "+
				  sdf.format(new Date(start))+" - "+
				  sdf.format(new Date(end)));
	frame.getContentPane().add(chart);
	frame.pack();
	frame.setSize(1000,700);
	frame.setVisible(true);

	double DARK_MLD = Math.toRadians(40.0);
	double BRIGHT_MLD = Math.toRadians(15.0);
	
	long time  = start;
	int  count1 = 0;
	int  count2 = 0;
	int  count3 = 0;
	double mld = 0.0;

	Tag         tag = null;
	User        user = null;
	Proposal    proposal = null;
	Group       group = null;
	Observation obs = null;
	Source      source = null;
	Position    target = null;
	    
	Root root = OSS_Utilities.fetchRoot();
	
	// Check it exists.
	if (root == null) {		
	    throw new IllegalArgumentException("Root not found");
	} 
	
	// Loop over time.
	while (time < end) {

	    // zero at start of inc
	    count1 = 0;
	    count2 = 0;
	    count3 = 0;

	    Iterator iTag = root.listAllTags();
	    while (iTag.hasNext()) {
		
		tag = (Tag)iTag.next();
	
		Iterator iUser = tag.listAllUsers();
		while (iUser.hasNext()) {
		    
		    user = (User)iUser.next();
		  
		    
		    Iterator it = user.listAllProposals();
		    while (it.hasNext()) {
			KVPair pair = (KVPair)it.next();
			String name = (String)pair.getKey();
			
			proposal = OSS_Utilities.fetchProposal(new Path(user.getFullPath(), name));

			//System.err.println("Checking proposal: "+proposal.getName());
			
			if (proposal != null) { 	 	    
			    Iterator ig = proposal.listAllGroups();
			    while (ig.hasNext()) {

				group = (Group)ig.next();

				//System.err.println("Checking Group: "+group.getName());

				if (group instanceof FixedGroup) {
				    
				    long ft = ((FixedGroup)group).getFixedTime();
				    
				    if ((time < ft) &&
					(ft < (time + inc)))
					graph4.addPoint((double)ft, 45.0);
				    
				}

				if (group instanceof MonitorGroup) {

				    MonitorGroup mg = (MonitorGroup)group;

				    // Is it available now..
				    
				    long   pstartDate    = mg.getStartDate();
				    long   period        = mg.getPeriod();
				    float  floatFraction = mg.getFloatFraction();
				    
				    double fPeriod = (double)( time - pstartDate ) / (double)period;
				    double iPeriod = Math.rint(fPeriod);
				    
				    // Not started yet
				    if (pstartDate > time) continue;
				    
				    long startFloat = pstartDate + 
					(long)((iPeriod - (double)floatFraction / 2.0)* (double)period);
				    long endFloat   = pstartDate + 
					(long)((iPeriod + (double)floatFraction / 2.0)* (double)period);
	
				    if ((startFloat <= time) && (endFloat >= time)) {
					count1++;

					// Now check if ALL targets can be seen
					
					boolean visible = true;
					
					Iterator io = group.listAllObservations();
					while (io.hasNext() && visible) {
					
					    obs = (Observation)io.next();

					    source = obs.getSource();
					    
					    if (source == null)
						visible = false;
					    else {
						target = source.getPosition();
						
						double el = target.getAltitude(time);
						
						if (el < limit)
						    visible = false;
					    }
					}

					if (visible) {
					    count2++;

					    // Now check for moon from ALL targets in Group
					
					    if (group.getMinimumLunar() == Group.DARK)
						mld = DARK_MLD;
					    else
						mld = BRIGHT_MLD;
					    
   
					    Position moon = Astrometry.getLunarPosition(time);

					    boolean faraway = true;
					    
					    io = group.listAllObservations();
					    while (io.hasNext() && faraway) {
						
						obs = (Observation)io.next();
						
						source = obs.getSource();
					    
						if (source == null)
						    faraway= false;
						else {
						    target = source.getPosition();
						    double ld = target.getAngularDistance(moon);
						    if (ld > mld)
							faraway = false;
						}
					    }
					    if (faraway)
						count3++;
					    
					}
				    }		    
				}

			    } // next group

			}

		    } // next proposal

		} // next user
		
	    } // next tag
	    
	    // Plot point at [time, count]
  
	    System.err.println("Time: "+sdf.format(new Date(time))+" In Float: "+count1+" Visible: "+count2);
	    
	    graph.addPoint((double)time, (double)count1);
	    graph2.addPoint((double)time, (double)count2);
	    graph3.addPoint((double)time, (double)count3);

	    try {Thread.sleep(100L); } catch (InterruptedException e) {}
	
	    chart.repaint();

	    time = time + inc;

	 
	} // next time inc.
	

    }


    public void printProposal(Proposal proposal) {


	// JDBC Connection thingy
	java.sql.Connection conn;
	try {
	    Class.forName("com.mysql.jdbc.Driver").newInstance();	
	    conn = DriverManager.getConnection(
					       "jdbc:mysql://localhost/ngat_testdb?user=root&password=appletart99ax");
	    System.err.println("SQL Driver got connection: "+conn);
	} catch (Exception e) {
	    e.printStackTrace();
	    throw new IllegalArgumentException("Error creating SQL Connection to IDMAP Table:");	    
	}


	System.err.println("\n\n\n==================================================================================");
	System.err.println("Proposal: "+proposal.getName());
	Path path = new Path(proposal.getFullPath()); 
	String tname = path.getTagByName();
	String uname = path.getUserByName();
	String pname = path.getProposalByName();

	int oid = 0;

	oid = qry(conn,"select id from idmap where path = 'PROP:"+tname+"/"+uname+"/"+pname+"'");
	
	System.err.println("DATABASE ID ["+oid+"]");
	
	Path p = new Path(proposal.getFullPath());
	
	System.err.println(" TAG: "+p.getTagByName()+" PI: "+p.getUserByName());
	
	System.err.println("Priority: "+proposal.getPriority());
	
	System.err.println("Activation: "+sdf.format(new Date(proposal.getActivationDate()))+" - "+
			   sdf.format(new Date(proposal.getExpiryDate())));
	
	double at = proposal.getAllocatedTime();
	System.err.println("Allocated time: "+at+" hrs, Used:"+proposal.getUsedTime()+" hrs");
	
	System.err.println("         Poor seeing     Average Seeing   Excellent seeing");
	System.err.println("Dark:  "+
			   at*proposal.getAllocatedFraction(Proposal.DARK, Proposal.POOR)+"("+proposal.getTimeUsed(Proposal.DARK, Proposal.POOR)+")"+
			   at*proposal.getAllocatedFraction(Proposal.DARK, Proposal.AVERAGE)+"("+proposal.getTimeUsed(Proposal.DARK, Proposal.AVERAGE)+")"+
			   at*proposal.getAllocatedFraction(Proposal.DARK, Proposal.EXCELLENT)+"("+proposal.getTimeUsed(Proposal.DARK, Proposal.EXCELLENT)+")"+
			   "\nBright:"+
			   at*proposal.getAllocatedFraction(Proposal.DARK, Proposal.POOR)+"("+proposal.getTimeUsed(Proposal.DARK, Proposal.POOR)+")"+
			   at*proposal.getAllocatedFraction(Proposal.DARK, Proposal.AVERAGE)+"("+proposal.getTimeUsed(Proposal.DARK, Proposal.AVERAGE)+")"+
			   at*proposal.getAllocatedFraction(Proposal.DARK, Proposal.EXCELLENT)+"("+proposal.getTimeUsed(Proposal.DARK, Proposal.EXCELLENT)+")");
	
	
	System.err.println("\n------------------------------");
	System.err.println("Groups");
	System.err.println("------------------------------\n");
	
	Iterator ig = proposal.listAllGroups();
	while (ig.hasNext()) {
	    
	    Group group = (Group)ig.next();
	    oid = qry(conn,"select id from idmap where path = 'GRP:"+tname+"/"+uname+"/"+pname+"/"+group.getName()+"'");
	    System.err.println("Group: "+group.getName()+" Type: "+group.getClass().getName()+
			       " Priority: "+group.getPriority()+" OID="+oid);
	    
	    System.err.println("Expires: "+sdf.format(new Date(group.getExpiryDate()))+ " Lock status: "+
			       (group.getLock() == 0 ? "UNLOCKED" : " Locked/"+group.getLock()));
	    
	    System.err.println("Min Seeing: "+Group.toSeeingString(group.getMinimumSeeing())+
			       " Min Lunar: "+Group.toLunarString(group.getMinimumLunar())+
			       " Twilight:  "+Group.toTwilightString(group.getTwilightUsageMode()));
	    
	    if (group instanceof MonitorGroup) {
		MonitorGroup mg = (MonitorGroup)group;
		
		System.err.println("\nStart monitoring: "+sdf.format(new Date(mg.getStartDate())));
		System.err.println("End montoring:    "+sdf.format(new Date(mg.getEndDate())));
	    
		int ts = (int)(mg.getPeriod()/1000);
		int h = ts/3600;
		int ms = ts - 3600*h;
		int m = ms/60;
		int s = ms - 60*m;    
		
		System.err.println("Period: "+h+"H "+m+"M "+s);
		
		int ws = (int)((float)ts*mg.getFloatFraction());
		h = ws/3600;
		ms = ws - 3600*h;
		m = ms/60;
		s = ms - 60*m;    
		
		System.err.println("Window size:"+h+"H "+m+"M "+s+"S");
		
		int cp = (int)(( System.currentTimeMillis() - mg.getStartDate() ) / mg.getPeriod() );
		
		System.err.println("Current period: "+cp);
		
	    } else if
		(group instanceof FixedGroup) {
		FixedGroup fg = (FixedGroup)group;
		
		System.err.println("\nFixed-time: "+sdf.format(new Date(fg.getFixedTime())));
		
		
	    }
	    
	    
	    System.err.println("\n------------------------------");
	    System.err.println("Observations");
	    System.err.println("------------------------------\n");
	    
	    Iterator io = group.listAllObservations();
	    
	    while (io.hasNext()) {
		
		Observation obs = (Observation)io.next();
		oid = qry(conn,"select id from idmap where path = 'OBS:"+tname+"/"+uname+"/"+pname+"/"+group.getName()+"/"+obs.getName()+"'");
		System.err.println("Observation: "+obs.getName()+" OID="+oid);
		
		System.err.println("Exposure: "+(obs.getExposeTime()/1000.0)+" secs"+ " Repeats X"+obs.getNumRuns());
		
		Source src = obs.getSource();
		
		System.err.println("Target: "+src);
		System.err.println("Instr:  "+obs.getInstrumentConfig());
		//System.err.println("Scope:  "+obs.getTelescopeConfig());
		
	    }
	    
	     System.err.println("------------------------------");
	     	    System.err.println("History");
 	    System.err.println("------------------------------");
	    
 	    java.util.List historyList = group.getHistory();
 	    if (historyList != null) {
		int kk = 0;
 		Iterator hist = historyList.iterator();
 		while (hist.hasNext()) {
		    
 		    Group.History history = (Group.History)hist.next();
		    oid = qry(conn,"select id from idmap where path = 'H:"+tname+"/"+uname+"/"+pname+"/"+group.getName()+"/"+(++kk)+"'");
 		    System.err.println(""+oid+": "+sdf.format(new Date(history.getDate())));
		    
		    // int ts = history.getTimeUsed();	   
//  		    int m = ts/60;
//  		    int s = ts - 60*m;
 		    // if (history.getDone()) 
//  			System.err.println("Completed in "+m+"M "+s+"S, "+
//  					   (history.getDetails() != null ? history.getDetails() : ""));
//  		    else
//  			System.err.println("Failed after "+m+"M "+s+"S due to "+
//  					   (history.getCode() != null ? history.getCode() : "NOT_KNOWN"));
		    
 		}
		
 	    }
	    
	}

	
	System.err.println("");
	
	
    }

    private int qry(java.sql.Connection connection, String query) {
	try {	 
	    System.err.println("Exec query ["+query+"]");
	    Statement statement = connection.createStatement();	  
	    ResultSet resultSet = statement.executeQuery(query);
	    while (resultSet.next()) {
		int oid = resultSet.getInt(1); 
		return oid;
	    }
	} catch (Exception e) {
	    //e.printStackTrace();
	    System.err.println("Qry:"+e);
	}
	return -1;
    }
   
}
